from starlette.middleware.base import BaseHTTPMiddleware
from fastapi import Request
import uuid
import time
from app.utils.log_config import get_logger

# 获取访问日志记录器
logger = get_logger("access")

class RequestMiddleware(BaseHTTPMiddleware):
    """
    请求中间件，主要功能：
    1. 为每个请求添加唯一的请求ID
    2. 记录请求开始和结束的日志
    3. 记录请求处理时间
    """
    
    async def dispatch(self, request: Request, call_next):
        # 生成请求ID
        request_id = str(uuid.uuid4())
        request.state.request_id = request_id
        
        # 记录请求开始信息
        path = request.url.path
        method = request.method
        client_host = request.client.host if request.client else "unknown"
        
        # 开始计时
        start_time = time.time()
        logger.info(f"Request started: {method} {path} [ID: {request_id}, Client: {client_host}]")
        
        # 处理请求
        try:
            import asyncio
            from fastapi import Response
            
            # 设置请求超时（30秒）
            try:
                response = await asyncio.wait_for(call_next(request), timeout=60.0)
            except asyncio.TimeoutError:
                process_time = time.time() - start_time
                logger.error(f"Request timeout: {method} {path} [ID: {request_id}, Time: {process_time:.3f}s]")
                return Response(
                    status_code=408,
                    content="Request Timeout",
                    headers={"X-Request-ID": request_id}
                )
            
            # 添加请求ID到响应头
            response.headers["X-Request-ID"] = request_id
            
            # 记录请求处理时间
            process_time = time.time() - start_time
            response.headers["X-Process-Time"] = str(process_time)
            
            # 记录请求完成信息
            status_code = response.status_code
            logger.info(f"Request completed: {method} {path} [ID: {request_id}, Status: {status_code}, Time: {process_time:.3f}s]")
            
            return response
            
        except Exception as e:
            # 记录异常信息
            process_time = time.time() - start_time
            logger.error(f"Request failed: {method} {path} [ID: {request_id}, Error: {str(e)}, Time: {process_time:.3f}s]")
            raise  # 重新抛出异常，由错误处理中间件处理 